package org.senseframework.support.open.api.helper;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.senseframework.support.core.utils.JSONUtils;
import org.senseframework.support.open.api.controller.encrypt.ApplicationEncryptHandler;
import org.senseframework.support.open.api.exception.ApiException;
import org.senseframework.support.open.api.service.ApiDefinition;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import java.util.*;

/**
 * User: lanjian
 */
public class ResponseHelper {

    private static Log log = LogFactory.getLog(ResponseHelper.class);

//    public interface MapData {
//        void assemble(Map map);
//    }

    public interface ResponseHandler {
        Map handler(String data);

        void log(Long total);

        void validate();

        String data() throws Exception;
//        void after(String status, String data);
//        void finallyDo(String status,String data);
    }


    public static Map handler(ResponseHandler handler) throws Exception {
        Map map = null;
        String data = null;
        try {
            handler.validate();
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            data = handler.data();
            log.info("======json=======" + data);
            map = handler.handler(data);
            stopWatch.stop();
            long total = stopWatch.getTotalTimeMillis();
            if (total > 500) {
                handler.log(total);
            }
//            handler.after(String.valueOf(map.get("status")),data);
        } catch (Exception ex) {
            throw ex;
        } finally {
//            handler.finallyDo(map == null ? "500" : String.valueOf(map.get("status")),data);
        }
        return map;
    }

    public static List dataToMaps(Collection source, IDataToMap dataToMap, boolean exception) {
        List list = new ArrayList();
        if (CollectionUtils.isEmpty(source)) {
//            if (exception) {
//                throw new ApiException("", ApiDefinition.NO_DATA_CODE);
//            }
            return list;
        } else {
            for (Object obj : source) {
                Map map = new HashMap();
                try {
                    dataToMap.dataToMap(map, obj);
                    list.add(map);
                } catch (Exception ex) {
                    log.info("dataToMaps exception,msg=" + ex.getMessage(), ex);
                    //nothing to do
                }
            }
        }
        return list;
    }

    public static List dataToMaps(Collection source, IDataToMap dataToMap) {
        return dataToMaps(source, dataToMap, false);
    }

    public static Map dataToMaps(String key, Collection source, IDataToMap dataToMap) {
        Map map = new HashMap();
        map.put(key, dataToMaps(source, dataToMap, false));
        return map;
    }

    public static void dataToMaps(String key, Map map, Collection source, IDataToMap dataToMap) {
        map.put(key, dataToMaps(source, dataToMap, false));
    }

    public static void dataToMaps(String key, Map map, Collection source, IDTO idto) {
        List list = sourceToList(source, idto);
        map.put(key, list);
    }

    private static List sourceToList(Collection source, IDTO idto,IProxyDTO proxyDTO) {
        List list = new ArrayList();
        if (!CollectionUtils.isEmpty(source)) {
            for (Object obj : source) {
                try {
                    Object target = idto.dto();
                    BeanUtils.copyProperties(target, obj);
                    list.add(proxyDTO.proxy(target));
                } catch (Exception ex) {
                    log.info("dataToMaps exception,msg=" + ex.getMessage(), ex);
                    //nothing to do
                }
            }
        }
        return list;
    }

    private static List sourceToList(Collection source, IDTO idto) {
        List list = new ArrayList();
        if (!CollectionUtils.isEmpty(source)) {
            for (Object obj : source) {
                try {
                    Object target = idto.dto();
                    BeanUtils.copyProperties(target, obj);
                    list.add(target);
                } catch (Exception ex) {
                    log.info("dataToMaps exception,msg=" + ex.getMessage(), ex);
                    //nothing to do
                }
            }
        }
        return list;
    }

    public static Map dataToMaps(String key, Collection source, IDTO idto) {
        List list = sourceToList(source, idto);
        Map map = new HashMap();
        map.put(key, list);
        return map;
    }

    public static Map dataToMaps(String key, Collection source, IDTO idto,IProxyDTO proxyDTO) {
        List list=sourceToList(source, idto,proxyDTO);
        Map map = new HashMap();
        map.put(key, list);
        return map;
    }

    public static Map dataToMap(String key, Object source, IDataToMap dataToMap) {
        Map map = new HashMap();
        if (source == null) {
            return map;
        }
        Map dmap = new HashMap();
        dataToMap.dataToMap(dmap, source);
        map.put(key, dmap);
        return map;
    }

    public static Map dataToMap(String key, Object source, IDTO idto) {
        Object target = idto.dto();
        Map map = new HashMap();
        if (source == null) {
            return map;
        }
        try {
            BeanUtils.copyProperties(target, source);

        } catch (Exception e) {
            e.printStackTrace();
        }
        map.put(key, target);
        return map;
    }

    public static Map dataToMap(String key, Object source, IDTO idto,IProxyDTO proxy) {
        Object target = idto.dto();
        Map map = new HashMap();
        if (source == null) {
            return map;
        }
        try {
            BeanUtils.copyProperties(target, source);
        } catch (Exception e) {
            e.printStackTrace();
        }
        map.put(key, proxy.proxy(target));
        return map;
    }

    public static void dataToMap(String key, Map map, Object source, IDataToMap dataToMap) {
        Map dmap = new HashMap();
        dataToMap.dataToMap(dmap, source);
        map.put(key, dmap);

    }


    public static Map response(Integer status, String message, Collection sources, IDataToMap dataToMap) {
        return response(status, message, dataToMaps(sources, dataToMap));
    }

    public static Map response(Integer status, String message, Object source, IDataToMap dataToMap) {
        if (source == null) {
            throw new ApiException("", ApiDefinition.NO_DATA_CODE);
        }
        Map map = new HashMap();
        dataToMap.dataToMap(map, source);
        return response(status, message, map);
    }


    public static Map response(Integer status, String message) {
        return response(status, message, null);
    }


    public static Map response(Integer status, String message, Object body) {
        return response(status, null, message, body);
    }

    public static Map response(Integer status, Map extend, String message, Object body) {
        Map map = new HashMap();
        map.put(ApiDefinition.STATUS_KEY, status);
        map.put(ApiDefinition.MESSAGE_KEY, message);
        if (body == null) {
            body = new HashMap();
        }
        map.put(ApiDefinition.BODY_KEY, body);
//            String _body = DigestUtils.encodeBase64(Des3Utils.des3EncodeECB(DigestUtils.md5(salt + ApiDefinition.E_KEY), JSONUtils.toJSONString(body)));

//        if (log.isDebugEnabled()) {
//            map.put(ApiDefinition.BODY_KEY + "_test", body);
//        }
//        if (extend != null) {
//            map.put(ApiDefinition.EXTEND_KEY, extend);
//            if (log.isDebugEnabled()) {
//                map.put(ApiDefinition.EXTEND_KEY + "_test", extend);
//            }
//        }
        return map;
    }


    public static Map success() {
        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE);
    }

    public static Map success(String message) {
        return response(ApiDefinition.SUCCESS_CODE, message);
    }

    public static Map success(String message, Object source, IDataToMap dataToMap) {
        return response(ApiDefinition.SUCCESS_CODE, message, source, dataToMap);
    }

    public static Map success(Object source, IDataToMap dataToMap) {
        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, source, dataToMap);
    }

    public static Map uploadSuccess(Map map) {
        return response(ApiDefinition.UPLOAD_SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, map);
    }

    public static Map success(Object object) {
        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, object);
    }


    public static Map success(Object object, String message) {
        return response(ApiDefinition.SUCCESS_CODE, message, object);
    }


//    public static Map success(Map map) {
//        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, map);
//    }

    public static Map success(Collection collection) {
        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, collection);
    }

    public static Map success(String message, Collection source, IDataToMap dataToMap) {
        return response(ApiDefinition.SUCCESS_CODE, message, source, dataToMap);
    }

    public static Map success(Collection source, IDataToMap dataToMap) {
        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, source, dataToMap);
    }

    public static Map success(Collection sources, String sourceKey, IDataToMap dataToMap) {
        Map map = new HashMap();
        map.put(sourceKey, dataToMaps(sources, dataToMap));
        return response(ApiDefinition.SUCCESS_CODE, ApiDefinition.SUCCESS_DEFAULT_MESSAGE, map);
    }

    public static Map fail() {
        return response(ApiDefinition.FAIL_CODE, ApiDefinition.FAIL_DEFAULT_MESSAGE);
    }

    public static Map fail(String message) {
        return response(ApiDefinition.FAIL_CODE, message);
    }

    public static Map failBusiness(String message) {
        return response(ApiDefinition.BUSINESS_ERROR_CODE, message);
    }


    public static void wrapper(Map map, ApplicationEncryptHandler encryptHandler, String key) {
        if (map == null) {
            return;
        }
        Object body = map.get(ApiDefinition.BODY_KEY);
        if (body != null) {
            String bodyJson = JSONUtils.toJSONString(body);
            map.put(ApiDefinition.BODY_KEY, encryptHandler.encode(key, bodyJson));
        }
    }


    public static Map fail(String message, int code) {
        return response(code, message);
    }

    public static Map empty() {
        return response(ApiDefinition.NO_DATA_CODE, "");
    }

    public static Map empty(String message) {
        return response(ApiDefinition.NO_DATA_CODE, message);
    }

}
